package org.sample.junit6.ex8;

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.ThrowingConsumer;
import org.sample.junit6.Calculator;
import org.sample.junit6.Strings;

import java.util.Collection;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;

/**
 * 动态测试示例
 * 展示 @TestFactory 和 DynamicTest 的使用，支持运行时生成测试用例
 */
public class DynamicTestSample {

    private final Calculator calculator = new Calculator();
    private final Strings strings = new Strings();

    /**
     * 基于集合的动态测试
     * 测试计算器的加法功能
     */
    @TestFactory
    Collection<DynamicTest> dynamicTestsFromCollection() {
        return List.of(
                dynamicTest("1 + 2 = 3", () -> assertEquals(3, calculator.add(1, 2))),
                dynamicTest("2 + 3 = 5", () -> assertEquals(5, calculator.add(2, 3))),
                dynamicTest("3 + 4 = 7", () -> assertEquals(7, calculator.add(3, 4))),
                dynamicTest("0 + 0 = 0", () -> assertEquals(0, calculator.add(0, 0))),
                dynamicTest("-1 + 1 = 0", () -> assertEquals(0, calculator.add(-1, 1)))
        );
    }

    /**
     * 基于流的动态测试
     * 测试字符串拼接功能
     */
    @TestFactory
    Stream<DynamicTest> dynamicTestsFromStream() {
        return Stream.of("a,b", "hello,world", "test,case", "junit,6")
                .map(input -> dynamicTest(
                        "concatenate: " + input,
                        () -> {
                            String[] parts = input.split(",");
                            String expected = parts[0] + parts[1];
                            String actual = strings.concat(parts[0], parts[1]);
                            assertEquals(expected, actual);
                        }
                ));
    }

    /**
     * 基于数据生成器的动态测试
     * 使用生成的测试数据进行批量测试
     */
    @TestFactory
    Stream<DynamicTest> dynamicTestsFromGenerator() {
        // 生成测试数据：字符串及其长度
        ThrowingConsumer<String> testExecutor = input -> {
            int expectedLength = input.length();
            int actualLength = input.length();
            assertEquals(expectedLength, actualLength,
                    String.format("String '%s' length should be %d", input, expectedLength));
        };

        // 生成测试名称和数据的函数
        return DynamicTest.stream(
                Stream.of("", "a", "ab", "abc", "JUnit6", "Dynamic Testing"),
                input -> "Length test for: '" + input + "'",
                testExecutor
        );
    }

    /**
     * 基于迭代器的动态测试
     * 测试数学运算
     */
    @TestFactory
    Stream<DynamicTest> dynamicTestsWithIterator() {
        return IntStream.range(0, 5)
                .mapToObj(i -> dynamicTest(
                        "Square test for " + i,
                        () -> {
                            int expected = i * i;
                            int result = i * i; // 简化的平方计算
                            assertEquals(expected, result,
                                    String.format("%d squared should be %d", i, expected));
                        }
                ));
    }

    /**
     * 混合类型的动态测试
     * 展示动态测试的灵活性
     */
    @TestFactory
    Collection<DynamicTest> mixedDynamicTests() {
        return List.of(
                // 算术测试
                dynamicTest("Addition: 5 + 3", () -> assertEquals(8, calculator.add(5, 3))),
                dynamicTest("Division exception", () ->
                        assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0))),

                // 字符串测试
                dynamicTest("Empty string check", () -> assertTrue(strings.isEmpty(""))),
                dynamicTest("Non-empty string check", () -> assertFalse(strings.isEmpty("test"))),

                // 复杂场景测试
                dynamicTest("String concatenation with empty", () -> {
                    assertEquals("test", strings.concat("test", ""));
                    assertEquals("test", strings.concat("", "test"));
                }),

                dynamicTest("Multiple operations", () -> {
                    Calculator calc = new Calculator();
                    int result = calc.add(2, 3);
                    result = calc.multiply(result, 4);
                    assertEquals(20, result);
                })
        );
    }

}
